/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package merlion.mrp.ppm.session;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import merlion.common.util.Consts;
import merlion.mrp.ppm.entity.BOM;
import merlion.mrp.ppm.entity.MRP;
import merlion.mrp.ppm.entity.WeeklyMPS;
import merlion.scm.rmpm.entity.RawMaterial;
import merlion.scm.rmpm.entity.RawMaterialInventoryRecord;
import merlion.scm.rmpm.session.RawMaterialPurchaseSessionBeanLocal;

/**
 *
 * @author Zhang Ying and Zhu Xin
 */
@Stateless
public class MRPSession implements MRPSessionLocal {

    @PersistenceContext
    private EntityManager entityManager;
    @EJB
    private MPSPlanningSessionLocal mpsSession;
    @EJB
    private MRPSessionLocal mrpSession;
    @EJB
    private RawMaterialPurchaseSessionBeanLocal rmSession;

    @Override
    public boolean checkAbleToCreateMRP(int month, Integer selectedYear) {
        //throw new UnsupportedOperationException("Not supported yet.");
        // check whether wmps avail
        WeeklyMPS wmps = mpsSession.getWeeklyMPS(selectedYear, month);
        if (wmps == null) {
            return false;
        } else {
            // check whether ahve created before
            Query query = entityManager.createQuery("SELECT m FROM MRP m WHERE m.startPeriodYear=:p1 AND m.startPeriodMonth=:p2");
            query.setParameter("p1", selectedYear);
            query.setParameter("p2", month);
            return query.getResultList().isEmpty();
        }
    }

    @Override
    public BOM getBOM(String materialName) {
        Query query = entityManager.createQuery("SELECT b FROM BOM b WHERE b.material.name=:p1");
        query.setParameter("p1", materialName);
        return (BOM) query.getSingleResult();
    }
    
    private BOM getBOM(Long id) {
        return entityManager.find(BOM.class, id);
    }

    @Override
    public boolean persistNewMrps(ArrayList<MRP> newMRPs, Long staffId) {
        try {
//            int i = 0;
            for (MRP m : newMRPs) {
//                MRP mrp = new MRP(m.getStartPeriodYear(), m.getStartPeriodMonth(), m.getDateCreated(), i);
//                mrp.setGrossRequirements(m.getGrossRequirements());
//                mrp.setPlannedInventory(m.getPlannedInventory());
//                mrp.setPlannedReceipts(m.getPlannedReceipts());
//                entityManager.merge(mrp);
//                Query query = entityManager.createQuery("SELECT m FROM MRP m WHERE m.mrpIdStr=:p1");
//                query.setParameter("p1", m.getMrpIdStr());
//                MRP mrp2 = (MRP) query.getSingleResult();
//                mrp2.setBom(getBOM(m.getBom().getId()));
//                entityManager.merge(mrp);
//                BOM bom = getBOM(m.getBom().getMaterial().getName());
//                m.setBom(bom);
                entityManager.merge(m);
//                i++;
            }
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public MRP getMRPById(Long id) {
        return entityManager.find(MRP.class, id);
    }
    
    @Override 
    public MRP getMRPByDateAndMaterial(Integer selectedYear, Integer selectedMonth, String materialName) {
        try {
            Query query = entityManager.createQuery("SELECT mrp FROM MRP mrp WHERE mrp.startPeriodYear=:p1 AND mrp.startPeriodMonth=:p2 AND mrp.bom.material.name =:p3");
            query.setParameter("p1", selectedYear);
            query.setParameter("p2", selectedMonth);
            query.setParameter("p3", materialName);
            if (query.getResultList().isEmpty()) {
                return null;
            }
            return (MRP) query.getSingleResult();
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    @Override
    public ArrayList<ArrayList<Long>> getWeeklyDemands(Integer startPeriodYear, Integer startPeriodMonth) {
        // return size of 4*5
        return mpsSession.getEachWeekDemandForOneMonth(startPeriodMonth, startPeriodYear);
    }

    @Override
    public Long getPlannedInventoryForPrevWeek(Integer startPeriodYear, Integer startPeriodMonth, BOM bom) {
        try {
            Integer month, year;
            if (startPeriodMonth == 1) {
                month = 12;
                year = startPeriodYear - 1;
            } else {
                month = startPeriodMonth - 1;
                year = startPeriodYear;
            }

            Query query = entityManager.createQuery("SELECT m FROM MRP m WHERE m.startPeriodYear=:p1 AND m.startPeriodMonth=:p2 AND m.bom.id=:p3");
            query.setParameter("p1", year);
            query.setParameter("p2", month);
            query.setParameter("p3", bom.getId());
            if (query.getResultList().isEmpty()) {
                // TODO: if no previous planned inventory, get the real inventory from SCM
                return 1500L; 
            } else {
                MRP m = (MRP) query.getSingleResult();
                return m.getPlannedInventory().get(m.getPlannedInventory().size() - 1).getLongValue();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return 0L;
        }
    }

    @Override
    public Collection<MRP> getAllMRPs() {
        Query query = entityManager.createQuery("SELECT m FROM MRP m");
        return query.getResultList();
    }

    @Override
    public boolean updateMRP(MRP selectedMRP) {
        try {
            entityManager.merge(selectedMRP);
            return true;
        }catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public Long getRawMaterialSafetyStockFromSCM(String name) {
        Query query = entityManager.createQuery("SELECT rmir FROM RawMaterialInventoryRecord rmir WHERE rmir.rawMaterial.name=:p1");
        query.setParameter("p1", name);
        RawMaterialInventoryRecord rmir = (RawMaterialInventoryRecord) query.getSingleResult();
        return new Long(Math.round(rmir.getOptimalStock()));
    }
    
    @Override
    public ArrayList<Long> getMRPPurchasePlan (Date date) {
        int selectedYear,selectedMonth,selectedWeek;
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date);
        selectedYear=cal1.get(Calendar.YEAR);
        selectedMonth = cal1.get(Calendar.MONTH)+1;
        cal1 = mpsSession.getFirstMondayOfMonth(selectedYear, selectedMonth);  //first monday of the month
        
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date);  //requested date
        selectedWeek = cal2.get(Calendar.WEEK_OF_YEAR) - cal1.get(Calendar.WEEK_OF_YEAR)+1;
        ArrayList<Long> mrpPurchasePlan = new ArrayList<Long>();
        int maxWeekNo = mpsSession.getNumberOfWeeks(selectedYear, selectedMonth);
        if(selectedWeek>maxWeekNo) {
            return null;
        }
        for (String materialName : Consts.allRawMaterialNames) {
            RawMaterial rm = rmSession.getRawMaterialbyName(materialName);      
            Long leadTime = rm.getLeadtime();
            int year = selectedYear,month, weekNo;
            if(selectedWeek+leadTime<=maxWeekNo) {
                month = selectedMonth;
                weekNo = selectedWeek+leadTime.intValue();
            }
            else {
                month = selectedMonth+1;
                weekNo = (selectedWeek+leadTime.intValue())%maxWeekNo;
            }
            if(month>12) {
                month = month%12;
                year = selectedYear+1;
            }
            MRP mrp = mrpSession.getMRPByDateAndMaterial(year, month, materialName);
            if(mrp==null) {
                return null;
            }
            else {
                mrpPurchasePlan.add(mrp.getPlannedReceipts().get(weekNo-1).getLongValue());
            }
        }
        return mrpPurchasePlan;
    }
    
//    public ArrayList<MRP> getMRPByMaterialNMonth (int year, int month, RawMaterial rm) {
//        Query query = entityManager.createQuery("SELECT mrp FROM MRP mrp WHERE mrp.startPeriodYear=:p1 AND mrp.startPeriodMonth=:p2");
//        query.setParameter("p1", year);
//        query.setParameter("p2", month);
//        return new ArrayList<MRP>(query.getResultList());
//    }
}
